package com.bondar.task1;


public class FindSinCosSeries {
	private final double step;
	private int precision;

	public FindSinCosSeries(double step) {
		this.step = step;
		this.precision = getPrecisionOfStep(step);
	}
	
	public double calculate(int threads, int N) throws InterruptedException {
		Summator[] sumList = new Summator[threads];
		double threadOffset = threads * step;
		
		for (int i = 0; i < threads; i++) {
			createThread(-N, N, threads, sumList, threadOffset, i);
		}
		
		return totalSum(sumList);
	}

	private double totalSum(Summator[] sumList)
			throws InterruptedException {
		
		double sum = 0.0;
		
		for (Summator item : sumList) {
			item.join();
			sum += item.getSum();
		}
		
		return sum;
	}

	private void createThread(
				double start, double end, 
				int threads, 
				Summator[] sumList,
				double threadOffset, int threadIndex) {
		
		Summator findSum = new Summator(start, end, threadOffset, threadIndex);
		sumList[threadIndex] = findSum;
		findSum.start();
	}
	
	private int getPrecisionOfStep(double n) {
		return (int) (1 / n);
	}

	private double roundTo(double n, int to) {
		return (double) Math.round(n * to) / to;
	}

	private class Summator extends Thread {
		private final double start;
		private final double end;
		private double sum;
		private double threadOffset;
		private int threadIndex;

		public Summator(double taskStart, double taskEnd, double threadOffset, int index) {
			this.start = taskStart;
			this.end = taskEnd;
			this.threadOffset = threadOffset;
			this.threadIndex = index;
			sum = 0.0;
		}
		
		public double getSum() {	return sum;		}

		@Override
		public void run() {
			for (double i = start + threadIndex*step; i <= end; i = roundTo(i + threadOffset, precision)) {
				sum += Math.sin(i) * Math.cos(i);
			}
		}
	}

}
